#ifndef	_CHATBOTAI_H
#define	_CHATBOTAI_H

#include "ChatRulesParser.h"
#include "ChatRulesLexer.h"

#ifdef __cplusplus
extern "C" {
#endif

#define SILENCE 10

struct AIGreeting_struct;

typedef struct AIKeyValue_struct {
	pANTLR3_UINT8					key;
	char							*value;

	struct AIKeyValue_struct		*next;
} AIKeyValue;

typedef struct AICategory_struct {
	pANTLR3_UINT8					name;
	unsigned						countGreetings;
	struct AIGreeting_struct		*firstGreeting;
	struct AIGreeting_struct		*lastGreeting;

	unsigned						countFallbacks;
	struct AIFallback_struct		*firstFallback;
	struct AIFallback_struct		*lastFallback;

	struct AIRule					*firstRule;
	struct AIRule					*lastRule;

	struct AICategory_struct		*next;
} AICategory;

typedef struct AIContext_struct {
    pANTLR3_INPUT_STREAM			input;
    pChatRulesLexer					lex;
    pANTLR3_COMMON_TOKEN_STREAM		tokens;
    pChatRulesParser				parser;

	struct AIKeyValue_struct		*firstKeyValue;
	struct AIKeyValue_struct		*lastKeyValue;

	struct AICategory_struct		*defaultCategory;
	struct AICategory_struct		*currentCategory;
	struct AICategory_struct		*firstCategory;
	struct AICategory_struct		*lastCategory;
} AIContext;

typedef struct AIContext_struct *pAIContext;

typedef struct AIGreeting_struct {
	pANTLR3_UINT8 value;
	struct AIRule *rule;
	struct AIGreeting_struct *next;
} AIGreeting;

typedef struct AIFallback_struct {
	pANTLR3_UINT8 value;
	struct AIRule *rule;
	struct AIFallback_struct *next;
} AIFallback;

enum AIActionType {
	AIActionType_reply,
	AIActionType_category,
	AIActionType_save,
};

struct AIActionReply {
	struct AIStringExpression *value;
};

struct AIActionCategory {
	struct AIStringExpression *value;
};

struct AIActionSave {
	pANTLR3_UINT8 key;
	struct AIStringExpression *value;
};

struct AIAction {
	enum AIActionType type;
	union
	{
		struct AIActionReply reply;
		struct AIActionCategory category;
		struct AIActionSave save;
	} action;
	struct AIAction *next;
};

enum AIConditionalExpressionType {
	AIConditionalExpressionType_parenthesis,
	AIConditionalExpressionType_contains,
	AIConditionalExpressionType_containss,
	AIConditionalExpressionType_starts,
	AIConditionalExpressionType_startss,
	AIConditionalExpressionType_not,
	AIConditionalExpressionType_or,
	AIConditionalExpressionType_and,
	AIConditionalExpressionType_remember,
	AIConditionalExpressionType_rememberas,
};

struct AIConditionalExpression_parenthesis
{
	struct AIConditionalExpression *expression;
};

struct AIConditionalExpression_contains
{
	pANTLR3_UINT8 value;
};

struct AIConditionalExpression_containss
{
	pANTLR3_UINT8 value;
};

struct AIConditionalExpression_starts
{
	pANTLR3_UINT8 value;
};

struct AIConditionalExpression_startss
{
	pANTLR3_UINT8 value;
};

struct AIConditionalExpression_remember
{
	pANTLR3_UINT8 value;
};

struct AIConditionalExpression_rememberas
{
	pANTLR3_UINT8 key;
	pANTLR3_UINT8 value;
};

struct AIConditionalExpression_not
{
	struct AIConditionalExpression *expression;
};

struct AIConditionalExpression_or
{
	struct AIConditionalExpression *expression1;
	struct AIConditionalExpression *expression2;
};

struct AIConditionalExpression_and
{
	struct AIConditionalExpression *expression1;
	struct AIConditionalExpression *expression2;
};

struct AIConditionalExpression {
	enum AIConditionalExpressionType type;
	union
	{
		struct AIConditionalExpression_parenthesis parenthesis;
		struct AIConditionalExpression_contains contains;
		struct AIConditionalExpression_containss containss;
		struct AIConditionalExpression_starts starts;
		struct AIConditionalExpression_starts startss;
		struct AIConditionalExpression_not not;
		struct AIConditionalExpression_or or;
		struct AIConditionalExpression_and and;
		struct AIConditionalExpression_remember remember;
		struct AIConditionalExpression_rememberas rememberas;
	} expression;
};

enum AIStringExpressionType {
	AIStringExpressionType_literal,
	AIStringExpressionType_parenthesis,
	AIStringExpressionType_concatenation,
	AIStringExpressionType_input,
	AIStringExpressionType_token,
};

struct AIStringExpression_literal
{
	pANTLR3_UINT8 value;
};

struct AIStringExpression_token
{
	pANTLR3_UINT8 value;
};

struct AIStringExpression_parenthesis
{
	struct AIStringExpression *expression;
};

struct AIStringExpression_concatenation
{
	struct AIStringExpression *expression1;
	struct AIStringExpression *expression2;
};

struct AIStringExpression_input
{
	int index;
};

struct AIStringExpression {
	enum AIStringExpressionType type;
	union
	{
		struct AIStringExpression_literal literal;
		struct AIStringExpression_parenthesis parenthesis;
		struct AIStringExpression_concatenation concatenation;
		struct AIStringExpression_input input;
		struct AIStringExpression_token token;
	} expression;
};

struct AIRule {
	struct AIConditionalExpression *expression;
	struct AIAction *firstAction;
	struct AIAction *lastAction;
	struct AIRule *next;
};

struct AIWord {
	char *value;
	struct AIWord *next;
};

struct AISentence {
	struct AIWord *firstWord;
	struct AIWord *lastWord;
};

AIContext* aiCreateContext(const char *rulesFilePath);
void aiDestroyContext(AIContext *ctx);
AICategory* aiAllocCategory(AIContext *ctx, pANTLR3_STRING name);
void aiDestroyCategory(AICategory *cat);
void aiSetKeyValue(AIContext *ctx, pANTLR3_UINT8 key, struct AIStringExpression *value, struct AISentence *input);
AIKeyValue* aiGetKeyValue(AIContext *ctx, pANTLR3_STRING key);
void aiDestroyKeyValue(AIKeyValue*);
struct AIGreeting_struct* aiAddGreeting(AIContext *ctx, pANTLR3_STRING greeting);
struct AIFallback_struct* aiAddFallback(AIContext *ctx, pANTLR3_STRING fallback);
void aiSayRandomGreeting(AIContext *ctx, struct AISentence *input);
void aiSayRandomFallback(AIContext *ctx, struct AISentence *input);

struct AIRule *aiAllocRule(void);
struct AIAction *aiAllocAction(enum AIActionType);

struct AIConditionalExpression *aiAllocConditionalExpression(void);
struct AIConditionalExpression *aiAllocStartsExpression(pANTLR3_STRING text);
struct AIConditionalExpression *aiAllocStartssExpression(pANTLR3_STRING text);
struct AIConditionalExpression *aiAllocRememberExpression(pANTLR3_STRING text);
struct AIConditionalExpression *aiAllocRememberAsExpression(pANTLR3_STRING text1, pANTLR3_STRING text2);
struct AIConditionalExpression *aiAllocContainsExpression(pANTLR3_STRING text);
struct AIConditionalExpression *aiAllocContainssExpression(pANTLR3_STRING text);
struct AIConditionalExpression *aiAllocParenthesisExpression(struct AIConditionalExpression *expression);
struct AIConditionalExpression *aiAllocNotExpression(struct AIConditionalExpression *expression);
struct AIConditionalExpression *aiAllocAndExpression(struct AIConditionalExpression *expression1, struct AIConditionalExpression *expression2);
struct AIConditionalExpression *aiAllocOrExpression(struct AIConditionalExpression *expression1, struct AIConditionalExpression *expression2);

struct AIStringExpression *aiAllocStringExpression(void);
struct AIStringExpression *aiAllocLiteralExpression(pANTLR3_STRING text);
struct AIStringExpression *aiAllocParenthesisStringExpression(struct AIStringExpression *expression);
struct AIStringExpression *aiAllocConcatenationExpression(struct AIStringExpression *expression1, struct AIStringExpression *expression2);
struct AIStringExpression *aiAllocInputExpression(pANTLR3_STRING index);
struct AIStringExpression *aiAllocTokenExpression(pANTLR3_STRING token);

void aiAddRule(AIContext *ctx, struct AIRule *);
void aiAddAction(struct AIRule *rule, struct AIAction *action);
void aiAddReplyAction(struct AIRule *rule, struct AIStringExpression *text);
void aiAddCategoryAction(struct AIRule *rule, struct AIStringExpression *text);
void aiAddSaveAction(struct AIRule *rule, pANTLR3_STRING key, struct AIStringExpression *value);

void aiFreeRule(struct AIRule *);
void aiFreeExpression(struct AIConditionalExpression *);
void aiFreeAction(struct AIAction *);

int aiEvalConditionalExpression(AIContext *ctx, struct AIConditionalExpression *, struct AISentence *input);
char* aiEvalStringExpression(AIContext *ctx, struct AIStringExpression *, struct AISentence *input);
struct AIRule *aiGetMatchingRule(AIContext *ctx, struct AISentence *input);
void aiExecuteRule(AIContext *ctx, struct AIRule *rule, struct AISentence *input);

struct AISentence *aiCreateSentence(char *input);
void aiDestroySentence(struct AISentence *sentence);
void aiSay(char *text);
int aiStrcmp(const char *str1, const char *str2);
int aiStrncmp(const char *str1, const char *str2, size_t n);
char *aiStrchr(const char *s, int c);
int aiStrncmp(const char *str1, const char *str2, size_t n);
int aiStrncmp(const char *str1, const char *str2, size_t n);
char *aiStrstr(const char *haystack, const char *needle);
void *aiMalloc(size_t size);
void *aiCalloc(size_t num, size_t size);

extern time_t t0;

#ifdef __cplusplus
}
#endif

#endif
